{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "第五周作业， 推荐系统\n",
    "\n",
    "刘茜茜\n",
    "\n",
    "2018.8.16"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 导入工具包"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from __future__ import division\n",
    "\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "\n",
    "import pickle as cPickle\n",
    "import scipy.io as sio\n",
    "import scipy.sparse as ss\n",
    "from numpy.random import random  \n",
    "from collections import defaultdict\n",
    "\n",
    "import matplotlib.pylab as plt\n",
    "import seaborn as sns\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 推荐系统(补充代码)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "class RecommonderSystem:\n",
    "    def __init__(self):\n",
    "        # 读入数据做初始化\n",
    "\n",
    "        #用户和活动新的索引\n",
    "        self.userIndex = cPickle.load(open(\"PE_userIndex.pkl\", 'rb'))\n",
    "        self.eventIndex = cPickle.load(open(\"PE_eventIndex.pkl\", 'rb'))\n",
    "        self.n_users = len(self.userIndex)\n",
    "        self.n_items = len(self.eventIndex)\n",
    "\n",
    "        #用户-活动关系矩阵R\n",
    "        #在train_SVD会重新从文件中读取,二者要求的格式不同，来不及统一了:(\n",
    "        self.userEventScores = sio.mmread(\"PE_userEventScores\").todense()\n",
    "\n",
    "        #倒排表\n",
    "        ##每个用户参加的事件\n",
    "        self.itemsForUser = cPickle.load(open(\"PE_eventsForUser.pkl\", 'rb'))\n",
    "        ##事件参加的用户\n",
    "        self.usersForItem = cPickle.load(open(\"PE_usersForEvent.pkl\", 'rb'))\n",
    "\n",
    "        #基于模型的协同过滤参数初始化,训练\n",
    "        self.init_SVD()\n",
    "        self.train_SVD(trainfile = \"train.csv\")\n",
    "\n",
    "        #根据用户属性计算出的用户之间的相似度\n",
    "        self.userSimMatrix = sio.mmread(\"US_userSimMatrix\").todense()\n",
    "\n",
    "        #根据活动属性计算出的活动之间的相似度\n",
    "        self.eventPropSim = sio.mmread(\"EV_eventPropSim\").todense()\n",
    "        self.eventContSim = sio.mmread(\"EV_eventContSim\").todense()\n",
    "\n",
    "        #每个用户的朋友的数目\n",
    "        self.numFriends = sio.mmread(\"UF_numFriends\")\n",
    "        #用户的每个朋友参加活动的分数对该用户的影响\n",
    "        self.userFriends = sio.mmread(\"UF_userFriends\").todense()\n",
    "\n",
    "        #活动本身的热度\n",
    "        self.eventPopularity = sio.mmread(\"EA_eventPopularity\").todense()\n",
    "\n",
    "    def init_SVD(self, K=20):\n",
    "        #初始化模型参数（for 基于模型的协同过滤SVD_CF）\n",
    "        self.K = K  \n",
    "\n",
    "        #init parameters\n",
    "        #bias\n",
    "        self.bi = np.zeros(self.n_items)  \n",
    "        self.bu = np.zeros(self.n_users)  \n",
    "\n",
    "        #the small matrix\n",
    "        self.P = np.zeros((self.n_users, K))\n",
    "        self.Q = np.zeros((K, self.n_items ))\n",
    "        # 使用随机值会使每次预测结果都不一样\n",
    "        #self.P = random((self.n_users,self.K))/10*(np.sqrt(self.K))\n",
    "        #self.Q = random((self.K, self.n_items))/10*(np.sqrt(self.K))  \n",
    "        self.mu=self.userEventScores.mean()              # 二维评分矩阵的平均值  \n",
    "          \n",
    "          \n",
    "    def train_SVD(self,trainfile = 'train.csv', steps=100,gamma=0.04,Lambda=0.15):\n",
    "        #训练SVD模型（for 基于模型的协同过滤SVD_CF）\n",
    "        #gamma：为学习率\n",
    "        #Lambda：正则参数\n",
    "        \n",
    "        #完整代码补充如下：\n",
    "        print(\"SVD Train...\")\n",
    "        R = self.userEventScores                          # 评分矩阵\n",
    "        mse = np.zeros((self.n_users, self.n_items))\n",
    "        mse_Iter = np.zeros(steps)    \n",
    "        # 训练模型参数\n",
    "        file = open(trainfile,'rb')  \n",
    "        file.readline().decode().strip().split(\",\")\n",
    "        records = file.readlines()\n",
    "        for step in range(steps):\n",
    "            for line in records:\n",
    "                cols = line.decode().strip().split(',')\n",
    "                user = (cols[0])\n",
    "                event = (cols[1])\n",
    "                u = self.userIndex[user]        # 用户的索引\n",
    "                i = self.eventIndex[event]      # 事件的索引\n",
    "                                    \n",
    "                eui = R[u, i] - self.pred_SVD(u, i)\n",
    "                # 按照公式迭代\n",
    "                self.P[u,:] += gamma*( eui*self.Q[:,i].T-Lambda*self.P[u,:] )  # 向量运算          \n",
    "                self.Q[:,i] += gamma*( eui*self.P[u,:].T-Lambda*self.Q[:,i] )  # 向量运算\n",
    "                self.bi[i] += gamma*(eui - Lambda*self.bi[i] )          # 标量计算 \n",
    "                self.bu[u] += gamma*(eui - Lambda*self.bu[u] )          # 标量计算\n",
    "                # 保存预测误差\n",
    "                mse[u,i] = eui**2           # 每个预测误差的平方 \n",
    "            mse_Iter[step] =mse.sum()  # 所有用户所有事件的总预测误差\n",
    "            gamma *= 0.98                   # 学习速率逐渐降低\n",
    "\n",
    "        file.close()    \n",
    "\n",
    "        plt.figure(figsize=(14,4))\n",
    "        plt.plot(range(len(mse_Iter)), mse_Iter)\n",
    "        plt.title('MSE of LFM_train')\n",
    "        plt.xlabel('step')\n",
    "        plt.ylabel('MSE')\n",
    "        plt.grid(True,linestyle='-.')       \n",
    "        \n",
    "        print(\"SVD trained\")\n",
    "        return mse_Iter\n",
    "\n",
    "    \n",
    "    def pred_SVD(self, uid, i_id):\n",
    "        #根据当前参数，预测用户uid对Item（i_id）的打分        \n",
    "        ans=self.mu + self.bi[i_id] + self.bu[uid] + np.dot(self.P[uid,:],self.Q[:,i_id])  \n",
    "\n",
    "        #将打分范围控制在0-1之间\n",
    "        if ans>1:  \n",
    "            return 1  \n",
    "        elif ans<0:  \n",
    "            return 0\n",
    "        return ans  \n",
    "\n",
    "    def sim_cal_UserCF(self, uid1, uid2 ):\n",
    "        #请补充基于用户的协同过滤中的两个用户uid1和uid2之间的相似度（根据两个用户对item打分的相似度）\n",
    "        similarity = 0.0\n",
    "          #if uid1==uid2:\n",
    "        #    return 1        # 若两个ID相同，则相似度为1\n",
    "        \n",
    "        # 第1步，找出uid1曾参加过的所有事件及对其评分，找出uid2曾参加过的所有事件及对其评分\n",
    "        uid1_allevent = self.itemsForUser[uid1]\n",
    "        if len(uid1_allevent)==0:\n",
    "            return 0\n",
    "        uid1_allscore=np.zeros(len(uid1_allevent))\n",
    "        tt=0\n",
    "        for e1 in uid1_allevent:\n",
    "            uid1_allscore[tt]=self.userEventScores[uid1,e1]     # uid1参加过的所有活动及对其评分\n",
    "            tt+=1\n",
    "        \n",
    "        uid2_allevent=self.itemsForUser[uid2]\n",
    "        if len(uid2_allevent)==0:\n",
    "            return 0\n",
    "        uid2_allscore=np.zeros(len(uid2_allevent))\n",
    "        tt=0\n",
    "        for e2 in uid2_allevent:\n",
    "            uid2_allscore[tt]=self.userEventScores[uid2,e2]     # uid2参加过的所有活动及对其评分\n",
    "            tt += 1\n",
    "            \n",
    "        # 第2步，找出uid1和uid2共同参加的事件集合，以及分别对每一个共同事件的评分\n",
    "        mut_event = uid1_allevent & uid2_allevent     # 两个集合做交集，求公共元素\n",
    "        if len(mut_event)==0:\n",
    "            return 0                                  # 交集为空，相似度为0\n",
    "        uid1_mulscore=np.zeros(len(mut_event))\n",
    "        uid2_mulscore=np.zeros(len(mut_event))\n",
    "        tt=0\n",
    "        for e_m in mut_event:\n",
    "            uid1_mulscore[tt]=self.userEventScores[uid1,e_m]\n",
    "            uid2_mulscore[tt]=self.userEventScores[uid2,e_m]\n",
    "            tt += 1\n",
    "            \n",
    "        # 第3步，根据以上结果，按照peasorns公式计算相关结果   \n",
    "        # 算分子\n",
    "        X = uid1_mulscore - uid1_mulscore.mean()    # 去中心化\n",
    "        Y = uid2_mulscore - uid2_mulscore.mean()    # 去中心化\n",
    "        mole= (X*Y).sum()\n",
    "        # 算分母\n",
    "        #X_1 = uid1_allscore - uid1_allscore.mean()\n",
    "        #Y_1=  uid2_allscore - uid2_allscore.mean() \n",
    "        #deno= ( (X_1*X_1).sum() * (Y_1*Y_1).sum() )**0.5       # 模值相乘\n",
    "        deno= ( (X*X).sum() * (Y*Y).sum() )**0.5  # 模值相乘\n",
    "        # 计算相似度\n",
    "        if deno==0:\n",
    "            similarity = 0\n",
    "        else:\n",
    "            similarity=mole/deno\n",
    "    \n",
    "        return similarity  \n",
    "\n",
    "    def userCFReco(self, userId, eventId):\n",
    "        \"\"\"\n",
    "        根据User-based协同过滤，得到event的推荐度\n",
    "        基本的伪代码思路如下：\n",
    "        for item i\n",
    "          for every other user v that has a preference for i\n",
    "            compute similarity s between u and v\n",
    "            incorporate v's preference for i weighted by s into running aversge\n",
    "        return top items ranked by weighted average\n",
    "        \"\"\"\n",
    "        ans = 0.0\n",
    "        #完整代码补充如下：\n",
    "        u = self.userIndex[userId]\n",
    "        i = self.eventIndex[eventId]\n",
    "        #第1步，找出参加过eventId的特定用户集合\n",
    "        user_some = self.usersForItem[i]\n",
    "        if len(user_some)==0:   \n",
    "            return self.mu                              # 如果该集合为空集，则协同推荐值为评分矩阵的平均值\n",
    "        #第2步，计算userId与这些特定用户的用户相似度\n",
    "        tt=0\n",
    "        sim=np.zeros(len(user_some))\n",
    "        for uid2 in user_some:\n",
    "            sim[tt]=self.sim_cal_UserCF(u, uid2)        # 将用户相似度值保存在矩阵sim中\n",
    "            tt += 1\n",
    "        #第3步，求出这些特定用户对eventId的评分\n",
    "        tt=0\n",
    "        score=np.zeros(len(user_some))\n",
    "        for uid2 in user_some:\n",
    "            score[tt]=self.userEventScores[uid2,i]\n",
    "            tt+=1\n",
    "        # 第4步，将第2步用户相似度和第3步的评分结果，加权相乘并累加求和，输出控制在[0,1]之间\n",
    "        if sim.sum()==0:\n",
    "            return self.mu\n",
    "        else:\n",
    "            ans= ( sim/sim.sum()*score ).sum()        # 加权、相乘、累加\n",
    "\n",
    "        if ans>1:\n",
    "            ans = 1\n",
    "        elif ans<0:\n",
    "            ans = 0            \n",
    "\n",
    "        return ans\n",
    "\n",
    "\n",
    "    def sim_cal_ItemCF(self, i_id1, i_id2):\n",
    "        #计算Item i_id1和i_id2之间的相似性\n",
    "        #完整代码补充如下：\n",
    "        similarity = 0.0\n",
    "\n",
    "        # 第1步，找出参加过事件i_id1的所有用户及对其评分，找出参加过事件i_id2的所有用户及对其评分\n",
    "        i1_alluser=self.usersForItem[i_id1]\n",
    "        if len(i1_alluser)==0:\n",
    "            return 0\n",
    "        i1_allscore=np.zeros(len(i1_alluser))\n",
    "        tt=0\n",
    "        for u1 in i1_alluser:\n",
    "            i1_allscore[tt]=self.userEventScores[u1, i_id1]  # 参加过i_id1的所有用户对其评分\n",
    "            tt+=1\n",
    "        \n",
    "        i2_alluser=self.usersForItem[i_id2]\n",
    "        if len(i2_alluser)==0:\n",
    "            return 0\n",
    "        i2_allscore=np.zeros(len(i2_alluser))\n",
    "        tt=0\n",
    "        for u2 in i2_alluser:\n",
    "            i2_allscore[tt]=self.userEventScores[u2, i_id2]   # 参加过i_id2的所有用户对其评分\n",
    "            tt += 1\n",
    "            \n",
    "        # 第2步，找出共同参加i_id1和i_id2的用户集合，以及每一个共同用户分别对i_id1和i_id2的评分\n",
    "        mut_user = i1_alluser & i2_alluser            # 两个集合做交集，求公共元素        \n",
    "        if len(mut_user)==0:\n",
    "            return 0                                  # 交集为空，相似度为0\n",
    "        i1_mulscore=np.zeros(len(mut_user))\n",
    "        i2_mulscore=np.zeros(len(mut_user))\n",
    "        tt=0\n",
    "        for u_m in mut_user:\n",
    "            i1_mulscore[tt]=self.userEventScores[u_m, i_id1]\n",
    "            i2_mulscore[tt]=self.userEventScores[u_m, i_id2]\n",
    "            tt += 1\n",
    "       \n",
    "        #第3步，根据以上结果，按照peasorns公式计算相关结果\n",
    "        # 算分子\n",
    "        X = i1_mulscore - i1_mulscore.mean()    # 去中心化\n",
    "        Y = i2_mulscore - i2_mulscore.mean()    # 去中心化\n",
    "        mole= (X*Y).sum()\n",
    "        # 算分母\n",
    "        #X_1 = i1_allscore - i1_allscore.mean()\n",
    "        #Y_1=  i1_allscore - i1_allscore.mean() \n",
    "        #deno= ( (X_1*X_1).sum() * (Y_1*Y_1).sum() )**0.5       # 模值相乘\n",
    "        deno= ( (X*X).sum() * (Y*Y).sum() )**0.5  # 模值相乘\n",
    "        # 计算相似度\n",
    "        if deno==0:\n",
    "            similarity = 0\n",
    "        else:\n",
    "            similarity=mole/deno\n",
    "        \n",
    "        return similarity   \n",
    "            \n",
    "    def eventCFReco(self, userId, eventId):    \n",
    "        \"\"\"\n",
    "        根据基于物品的协同过滤，得到Event的推荐度\n",
    "        基本的伪代码思路如下：\n",
    "        for item i \n",
    "            for every item j tht u has a preference for\n",
    "                compute similarity s between i and j\n",
    "                add u's preference for j weighted by s to a running average\n",
    "        return top items, ranked by weighted average\n",
    "        \"\"\"\n",
    "        # 代码补充如下\n",
    "        u = self.userIndex[userId]\n",
    "        i = self.eventIndex[eventId]\n",
    "        \n",
    "        #第1步，找出用户userId参加过的特定事件集合\n",
    "        Item_some = self.itemsForUser[u]\n",
    "        if len(Item_some)==0:   \n",
    "            return self.mu                               # 如果该集合为空集，则协同推荐值为评分矩阵的平均值\n",
    "\n",
    "        #第2步，计算eventId与这些特定事件的事件相似度\n",
    "        tt=0\n",
    "        sim=np.zeros(len(Item_some))\n",
    "        for i_id2 in Item_some:\n",
    "            sim[tt]=self.sim_cal_ItemCF(i, i_id2)        # 将用户相似度值保存在矩阵sim中\n",
    "            tt += 1\n",
    "            \n",
    "        #第3步，找出userId对这些特定特定事件的评分\n",
    "        tt=0\n",
    "        score=np.zeros(len(Item_some))\n",
    "        for i_id2 in Item_some:\n",
    "            score[tt]=self.userEventScores[u,i_id2]\n",
    "            tt+=1\n",
    "       \n",
    "        # 第4步，将第2步事件相似度和第3步的评分结果，加权相乘并累加求和，输出控制在[0,1]之间\n",
    "        if sim.sum()==0:\n",
    "            return self.mu\n",
    "        else:\n",
    "            pred= ( sim/sim.sum()*score ).sum()        # 加权、相乘、累加\n",
    "\n",
    "        if pred>1:\n",
    "            pred = 1\n",
    "        elif pred<0:\n",
    "            pred = 0            \n",
    "        \n",
    "        return pred\n",
    "    \n",
    "    def svdCFReco(self, userId, eventId):\n",
    "        #基于模型的协同过滤, SVD++/LFM\n",
    "        u = self.userIndex[userId]\n",
    "        i = self.eventIndex[eventId]\n",
    "\n",
    "        return self.pred_SVD(u,i)\n",
    "\n",
    "    def userReco(self, userId, eventId):\n",
    "        \"\"\"\n",
    "        类似基于User-based协同过滤，只是用户之间的相似度由用户本身的属性得到，计算event的推荐度\n",
    "        基本的伪代码思路如下：\n",
    "        for item i\n",
    "          for every other user v that has a preference for i\n",
    "            compute similarity s between u and v\n",
    "            incorporate v's preference for i weighted by s into running aversge\n",
    "        return top items ranked by weighted average\n",
    "        \"\"\"\n",
    "        i = self.userIndex[userId]\n",
    "        j = self.eventIndex[eventId]\n",
    "\n",
    "        vs = self.userEventScores[:, j]\n",
    "        sims = self.userSimMatrix[i, :]\n",
    "\n",
    "        prod = sims * vs\n",
    "\n",
    "        try:\n",
    "            return prod[0, 0] - self.userEventScores[i, j]\n",
    "        except IndexError:\n",
    "            return 0\n",
    "\n",
    "    def eventReco(self, userId, eventId):\n",
    "        \"\"\"\n",
    "        类似基于Item-based协同过滤，只是item之间的相似度由item本身的属性得到，计算Event的推荐度\n",
    "        基本的伪代码思路如下：\n",
    "        for item i \n",
    "          for every item j that u has a preference for\n",
    "            compute similarity s between i and j\n",
    "            add u's preference for j weighted by s to a running average\n",
    "        return top items, ranked by weighted average\n",
    "        \"\"\"\n",
    "        i = self.userIndex[userId]\n",
    "        j = self.eventIndex[eventId]\n",
    "        js = self.userEventScores[i, :]\n",
    "        psim = self.eventPropSim[:, j]\n",
    "        csim = self.eventContSim[:, j]\n",
    "        pprod = js * psim\n",
    "        cprod = js * csim\n",
    "\n",
    "        pscore = 0\n",
    "        cscore = 0\n",
    "        try:\n",
    "            pscore = pprod[0, 0] - self.userEventScores[i, j]\n",
    "        except IndexError:\n",
    "            pass\n",
    "        try:\n",
    "            cscore = cprod[0, 0] - self.userEventScores[i, j]\n",
    "        except IndexError:\n",
    "              pass\n",
    "        return pscore, cscore\n",
    "\n",
    "    def userPop(self, userId):\n",
    "        \"\"\"\n",
    "        基于用户的朋友个数来推断用户的社交程度\n",
    "        主要的考量是如果用户的朋友非常多，可能会更倾向于参加各种社交活动\n",
    "        \"\"\"\n",
    "        if userId in self.userIndex:\n",
    "            i = self.userIndex[userId]\n",
    "            try:\n",
    "                return self.numFriends[0, i]\n",
    "            except IndexError:\n",
    "                return 0\n",
    "        else:\n",
    "            return 0\n",
    "\n",
    "    def friendInfluence(self, userId):\n",
    "        \"\"\"\n",
    "        朋友对用户的影响\n",
    "        主要考虑用户所有的朋友中，有多少是非常喜欢参加各种社交活动/event的\n",
    "        用户的朋友圈如果都积极参与各种event，可能会对当前用户有一定的影响\n",
    "        \"\"\"\n",
    "        nusers = np.shape(self.userFriends)[1]\n",
    "        i = self.userIndex[userId]\n",
    "        return (self.userFriends[i, :].sum(axis=0) / nusers)[0,0]\n",
    "\n",
    "    def eventPop(self, eventId):\n",
    "        \"\"\"\n",
    "        本活动本身的热度\n",
    "        主要是通过参与的人数来界定的\n",
    "        \"\"\"\n",
    "        i = self.eventIndex[eventId]\n",
    "        return self.eventPopularity[i, 0]\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 生成新的数据集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "def generateRSData(RS, train=True, header=True):\n",
    "    \"\"\"\n",
    "    把前面user-based协同过滤 和 item-based协同过滤，以及各种热度和影响度作为特征组合在一起\n",
    "    生成新的训练数据，用于分类器分类使用\n",
    "    \"\"\"\n",
    "    fn = \"train.csv\" if train else \"test.csv\"\n",
    "    fin = open(fn, 'rb')\n",
    "    fout = open(\"RS_\" + fn, 'w')\n",
    "    \n",
    "    #忽略第一行（列名字）\n",
    "    fin.readline().decode().strip().split(\",\")\n",
    "    \n",
    "    # write output header\n",
    "    if header:\n",
    "        ocolnames = [\"invited\", \"userCF_reco\", \"evtCF_reco\",\"svdCF_reco\",\"user_reco\",\\\n",
    "                        \"evt_p_reco\",\"evt_c_reco\", \"user_pop\", \"frnd_infl\", \"evt_pop\"]\n",
    "    \n",
    "        if train:\n",
    "            ocolnames.append(\"interested\")\n",
    "            ocolnames.append(\"not_interested\")\n",
    "        fout.write(\",\".join(ocolnames) + \"\\n\")\n",
    "    \n",
    "    ln = 0\n",
    "    for line in fin.readlines():\n",
    "        ln += 1\n",
    "        if ln%1000 == 0:\n",
    "              print(\"%s:%d (userId, eventId)=(%s, %s)\" % (fn, ln, userId, eventId))\n",
    "              #break;\n",
    "\n",
    "        cols = line.decode().strip().split(\",\")\n",
    "        userId = cols[0]\n",
    "        eventId = cols[1]\n",
    "        invited = cols[2]\n",
    "\n",
    "        userCF_reco = RS.userCFReco(userId, eventId)\n",
    "        itemCF_reco = RS.eventCFReco(userId, eventId)\n",
    "        svdCF_reco = RS.svdCFReco(userId, eventId)\n",
    "\n",
    "        user_reco = RS.userReco(userId, eventId)\n",
    "        evt_p_reco, evt_c_reco = RS.eventReco(userId, eventId)\n",
    "        user_pop = RS.userPop(userId)\n",
    "\n",
    "        frnd_infl = RS.friendInfluence(userId)\n",
    "        evt_pop = RS.eventPop(eventId)\n",
    "        ocols = [invited, userCF_reco, itemCF_reco, svdCF_reco,user_reco, evt_p_reco,evt_c_reco, user_pop, frnd_infl, evt_pop]\n",
    "\n",
    "        if train:\n",
    "            ocols.append(cols[4]) # interested\n",
    "            ocols.append(cols[5]) # not_interested\n",
    "        fout.write(\",\".join(map(lambda x: str(x), ocols)) + \"\\n\")\n",
    "    \n",
    "    fin.close()\n",
    "    fout.close()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "SVD Train...\n",
      "SVD trained\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 1008x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "RS = RecommonderSystem()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "生成训练数据...\n",
      "\n",
      "train.csv:1000 (userId, eventId)=(272886293, 199858305)\n",
      "train.csv:2000 (userId, eventId)=(527523423, 3272728211)\n",
      "train.csv:3000 (userId, eventId)=(811791433, 524756826)\n",
      "train.csv:4000 (userId, eventId)=(1107615001, 173949238)\n",
      "train.csv:5000 (userId, eventId)=(1414301782, 2652356640)\n",
      "train.csv:6000 (userId, eventId)=(1747091728, 2131379889)\n",
      "train.csv:7000 (userId, eventId)=(2071842684, 1076364848)\n",
      "train.csv:8000 (userId, eventId)=(2338481531, 2525447278)\n",
      "train.csv:9000 (userId, eventId)=(2650493630, 87962584)\n",
      "train.csv:10000 (userId, eventId)=(2903662804, 2791462807)\n",
      "train.csv:11000 (userId, eventId)=(3176074542, 3459485614)\n",
      "train.csv:12000 (userId, eventId)=(3410667855, 1063772489)\n",
      "train.csv:13000 (userId, eventId)=(3686871863, 53495098)\n",
      "train.csv:14000 (userId, eventId)=(3944021305, 2096772901)\n",
      "train.csv:15000 (userId, eventId)=(4197193550, 1628057176)\n",
      "生成预测数据...\n",
      "\n",
      "test.csv:1000 (userId, eventId)=(433510318, 4244463632)\n",
      "test.csv:2000 (userId, eventId)=(813611885, 2036538169)\n",
      "test.csv:3000 (userId, eventId)=(1210932037, 2529072432)\n",
      "test.csv:4000 (userId, eventId)=(1623287180, 1626678328)\n",
      "test.csv:5000 (userId, eventId)=(2083900381, 2529072432)\n",
      "test.csv:6000 (userId, eventId)=(2528161539, 4025975316)\n",
      "test.csv:7000 (userId, eventId)=(2927772127, 1532377761)\n",
      "test.csv:8000 (userId, eventId)=(3393388475, 680270887)\n",
      "test.csv:9000 (userId, eventId)=(3828963415, 3067222491)\n",
      "test.csv:10000 (userId, eventId)=(4180064266, 2658555390)\n"
     ]
    }
   ],
   "source": [
    "print(\"生成训练数据...\\n\")\n",
    "generateRSData(RS,train=True,  header=True)\n",
    "\n",
    "print(\"生成预测数据...\\n\")\n",
    "generateRSData(RS, train=False, header=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 查看新生成的数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>invited</th>\n",
       "      <th>userCF_reco</th>\n",
       "      <th>evtCF_reco</th>\n",
       "      <th>svdCF_reco</th>\n",
       "      <th>user_reco</th>\n",
       "      <th>evt_p_reco</th>\n",
       "      <th>evt_c_reco</th>\n",
       "      <th>user_pop</th>\n",
       "      <th>frnd_infl</th>\n",
       "      <th>evt_pop</th>\n",
       "      <th>interested</th>\n",
       "      <th>not_interested</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.005369</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>8.911768e-01</td>\n",
       "      <td>8.911768e-01</td>\n",
       "      <td>0.000231</td>\n",
       "      <td>0.0</td>\n",
       "      <td>-0.000664</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.028582</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>1.691736e-01</td>\n",
       "      <td>1.691736e-01</td>\n",
       "      <td>0.000231</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.000312</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>0</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>0.591891</td>\n",
       "      <td>0.439084</td>\n",
       "      <td>54.414964</td>\n",
       "      <td>-1.000000e+00</td>\n",
       "      <td>-1.000000e+00</td>\n",
       "      <td>0.000231</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.002928</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>0</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.027925</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>1.066331e+00</td>\n",
       "      <td>1.066331e+00</td>\n",
       "      <td>0.000231</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.000273</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>0</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.168161</td>\n",
       "      <td>0.173853</td>\n",
       "      <td>10.687096</td>\n",
       "      <td>2.507789e-07</td>\n",
       "      <td>2.507789e-07</td>\n",
       "      <td>0.000231</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.001093</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>0</td>\n",
       "      <td>0.027027</td>\n",
       "      <td>0.213934</td>\n",
       "      <td>0.221280</td>\n",
       "      <td>15.771665</td>\n",
       "      <td>2.261498e-07</td>\n",
       "      <td>2.261498e-07</td>\n",
       "      <td>0.000231</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.003982</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>0</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.141156</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>1.524557e+00</td>\n",
       "      <td>1.524557e+00</td>\n",
       "      <td>0.000160</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.000273</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>0</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>0.649395</td>\n",
       "      <td>13.124750</td>\n",
       "      <td>3.165701e-02</td>\n",
       "      <td>3.165701e-02</td>\n",
       "      <td>0.000160</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.009603</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>0</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>0.500619</td>\n",
       "      <td>10.053481</td>\n",
       "      <td>-4.849421e-01</td>\n",
       "      <td>-4.849421e-01</td>\n",
       "      <td>0.000160</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.020611</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>0</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.295589</td>\n",
       "      <td>0.266206</td>\n",
       "      <td>1.524558e+00</td>\n",
       "      <td>1.524558e+00</td>\n",
       "      <td>0.000160</td>\n",
       "      <td>0.0</td>\n",
       "      <td>-0.000234</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   invited  userCF_reco  evtCF_reco  svdCF_reco  user_reco    evt_p_reco  \\\n",
       "0        0     0.000000    0.000091    0.005369   0.000000  8.911768e-01   \n",
       "1        0     0.000000    0.000091    0.028582   0.000000  1.691736e-01   \n",
       "2        0     1.000000    0.591891    0.439084  54.414964 -1.000000e+00   \n",
       "3        0     0.000000    0.000091    0.027925   0.000000  1.066331e+00   \n",
       "4        0     0.000000    0.168161    0.173853  10.687096  2.507789e-07   \n",
       "5        0     0.027027    0.213934    0.221280  15.771665  2.261498e-07   \n",
       "6        0     0.000000    0.000091    0.141156   0.000000  1.524557e+00   \n",
       "7        0     1.000000    1.000000    0.649395  13.124750  3.165701e-02   \n",
       "8        0     1.000000    1.000000    0.500619  10.053481 -4.849421e-01   \n",
       "9        0     0.000000    0.000000    0.295589   0.266206  1.524558e+00   \n",
       "\n",
       "     evt_c_reco  user_pop  frnd_infl   evt_pop  interested  not_interested  \n",
       "0  8.911768e-01  0.000231        0.0 -0.000664           0               0  \n",
       "1  1.691736e-01  0.000231        0.0  0.000312           0               0  \n",
       "2 -1.000000e+00  0.000231        0.0  0.002928           1               0  \n",
       "3  1.066331e+00  0.000231        0.0  0.000273           0               0  \n",
       "4  2.507789e-07  0.000231        0.0  0.001093           0               0  \n",
       "5  2.261498e-07  0.000231        0.0  0.003982           0               0  \n",
       "6  1.524557e+00  0.000160        0.0  0.000273           0               0  \n",
       "7  3.165701e-02  0.000160        0.0  0.009603           1               0  \n",
       "8 -4.849421e-01  0.000160        0.0  0.020611           1               0  \n",
       "9  1.524558e+00  0.000160        0.0 -0.000234           0               0  "
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#读取数据\n",
    "rs_train = pd.read_csv(\"RS_train.csv\")\n",
    "rs_train.head(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>invited</th>\n",
       "      <th>userCF_reco</th>\n",
       "      <th>evtCF_reco</th>\n",
       "      <th>svdCF_reco</th>\n",
       "      <th>user_reco</th>\n",
       "      <th>evt_p_reco</th>\n",
       "      <th>evt_c_reco</th>\n",
       "      <th>user_pop</th>\n",
       "      <th>frnd_infl</th>\n",
       "      <th>evt_pop</th>\n",
       "      <th>interested</th>\n",
       "      <th>not_interested</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>count</th>\n",
       "      <td>15398.000000</td>\n",
       "      <td>15398.000000</td>\n",
       "      <td>15398.000000</td>\n",
       "      <td>15398.000000</td>\n",
       "      <td>15398.000000</td>\n",
       "      <td>1.539800e+04</td>\n",
       "      <td>1.539800e+04</td>\n",
       "      <td>1.539800e+04</td>\n",
       "      <td>1.539800e+04</td>\n",
       "      <td>15398.000000</td>\n",
       "      <td>15398.000000</td>\n",
       "      <td>15398.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>mean</th>\n",
       "      <td>0.042473</td>\n",
       "      <td>0.267235</td>\n",
       "      <td>0.133128</td>\n",
       "      <td>0.247355</td>\n",
       "      <td>4.015896</td>\n",
       "      <td>8.413532e-01</td>\n",
       "      <td>8.413532e-01</td>\n",
       "      <td>2.944272e-04</td>\n",
       "      <td>1.723655e-07</td>\n",
       "      <td>0.002531</td>\n",
       "      <td>0.268282</td>\n",
       "      <td>0.033381</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>std</th>\n",
       "      <td>0.201672</td>\n",
       "      <td>0.434694</td>\n",
       "      <td>0.324157</td>\n",
       "      <td>0.296637</td>\n",
       "      <td>13.782441</td>\n",
       "      <td>1.711798e+00</td>\n",
       "      <td>1.711798e+00</td>\n",
       "      <td>2.687068e-04</td>\n",
       "      <td>7.127684e-06</td>\n",
       "      <td>0.010303</td>\n",
       "      <td>0.443079</td>\n",
       "      <td>0.179635</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>min</th>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>-1.000000e+00</td>\n",
       "      <td>-1.000000e+00</td>\n",
       "      <td>2.679976e-07</td>\n",
       "      <td>0.000000e+00</td>\n",
       "      <td>-0.035288</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>25%</th>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.023965</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>1.920141e-08</td>\n",
       "      <td>1.920141e-08</td>\n",
       "      <td>1.018391e-04</td>\n",
       "      <td>0.000000e+00</td>\n",
       "      <td>0.000039</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>50%</th>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.074458</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>5.552025e-01</td>\n",
       "      <td>5.552025e-01</td>\n",
       "      <td>2.181500e-04</td>\n",
       "      <td>0.000000e+00</td>\n",
       "      <td>0.000546</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>75%</th>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.920023</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.450938</td>\n",
       "      <td>1.128589</td>\n",
       "      <td>1.172813e+00</td>\n",
       "      <td>1.172813e+00</td>\n",
       "      <td>3.934204e-04</td>\n",
       "      <td>0.000000e+00</td>\n",
       "      <td>0.001835</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>0.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>max</th>\n",
       "      <td>1.000000</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>179.558659</td>\n",
       "      <td>2.957971e+01</td>\n",
       "      <td>2.957971e+01</td>\n",
       "      <td>1.315064e-03</td>\n",
       "      <td>2.948983e-04</td>\n",
       "      <td>0.390313</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>1.000000</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "            invited   userCF_reco    evtCF_reco    svdCF_reco     user_reco  \\\n",
       "count  15398.000000  15398.000000  15398.000000  15398.000000  15398.000000   \n",
       "mean       0.042473      0.267235      0.133128      0.247355      4.015896   \n",
       "std        0.201672      0.434694      0.324157      0.296637     13.782441   \n",
       "min        0.000000      0.000000      0.000000      0.000000      0.000000   \n",
       "25%        0.000000      0.000000      0.000091      0.023965      0.000000   \n",
       "50%        0.000000      0.000000      0.000091      0.074458      0.000000   \n",
       "75%        0.000000      0.920023      0.000091      0.450938      1.128589   \n",
       "max        1.000000      1.000000      1.000000      1.000000    179.558659   \n",
       "\n",
       "         evt_p_reco    evt_c_reco      user_pop     frnd_infl       evt_pop  \\\n",
       "count  1.539800e+04  1.539800e+04  1.539800e+04  1.539800e+04  15398.000000   \n",
       "mean   8.413532e-01  8.413532e-01  2.944272e-04  1.723655e-07      0.002531   \n",
       "std    1.711798e+00  1.711798e+00  2.687068e-04  7.127684e-06      0.010303   \n",
       "min   -1.000000e+00 -1.000000e+00  2.679976e-07  0.000000e+00     -0.035288   \n",
       "25%    1.920141e-08  1.920141e-08  1.018391e-04  0.000000e+00      0.000039   \n",
       "50%    5.552025e-01  5.552025e-01  2.181500e-04  0.000000e+00      0.000546   \n",
       "75%    1.172813e+00  1.172813e+00  3.934204e-04  0.000000e+00      0.001835   \n",
       "max    2.957971e+01  2.957971e+01  1.315064e-03  2.948983e-04      0.390313   \n",
       "\n",
       "         interested  not_interested  \n",
       "count  15398.000000    15398.000000  \n",
       "mean       0.268282        0.033381  \n",
       "std        0.443079        0.179635  \n",
       "min        0.000000        0.000000  \n",
       "25%        0.000000        0.000000  \n",
       "50%        0.000000        0.000000  \n",
       "75%        1.000000        0.000000  \n",
       "max        1.000000        1.000000  "
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rs_train.describe()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>invited</th>\n",
       "      <th>userCF_reco</th>\n",
       "      <th>evtCF_reco</th>\n",
       "      <th>svdCF_reco</th>\n",
       "      <th>user_reco</th>\n",
       "      <th>evt_p_reco</th>\n",
       "      <th>evt_c_reco</th>\n",
       "      <th>user_pop</th>\n",
       "      <th>frnd_infl</th>\n",
       "      <th>evt_pop</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.000118</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.002342</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.000118</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.000507</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>0</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.000118</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.000976</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>0</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.000118</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.001171</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>0</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.000118</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.000781</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>0</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.000118</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>0</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.000118</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.000429</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>0</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.000009</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.000234</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>0</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.000009</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.002420</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>0</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.000009</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.000429</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   invited  userCF_reco  evtCF_reco  svdCF_reco  user_reco  evt_p_reco  \\\n",
       "0        0     0.000091    0.000091    0.000091        0.0         0.0   \n",
       "1        0     0.000091    0.000091    0.000091        0.0         0.0   \n",
       "2        0     0.000091    0.000091    0.000091        0.0         0.0   \n",
       "3        0     0.000091    0.000091    0.000091        0.0         0.0   \n",
       "4        0     0.000091    0.000091    0.000091        0.0         0.0   \n",
       "5        0     0.000091    0.000091    0.000091        0.0         0.0   \n",
       "6        0     0.000091    0.000091    0.000091        0.0         0.0   \n",
       "7        0     0.000091    0.000091    0.000091        0.0         0.0   \n",
       "8        0     0.000091    0.000091    0.000091        0.0         0.0   \n",
       "9        0     0.000091    0.000091    0.000091        0.0         0.0   \n",
       "\n",
       "   evt_c_reco  user_pop  frnd_infl   evt_pop  \n",
       "0         0.0  0.000118        0.0  0.002342  \n",
       "1         0.0  0.000118        0.0  0.000507  \n",
       "2         0.0  0.000118        0.0  0.000976  \n",
       "3         0.0  0.000118        0.0  0.001171  \n",
       "4         0.0  0.000118        0.0  0.000781  \n",
       "5         0.0  0.000118        0.0  0.000000  \n",
       "6         0.0  0.000118        0.0  0.000429  \n",
       "7         0.0  0.000009        0.0  0.000234  \n",
       "8         0.0  0.000009        0.0  0.002420  \n",
       "9         0.0  0.000009        0.0  0.000429  "
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#读取新生成的训练数据\n",
    "rs_test = pd.read_csv(\"RS_test.csv\")\n",
    "rs_test.head(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>invited</th>\n",
       "      <th>userCF_reco</th>\n",
       "      <th>evtCF_reco</th>\n",
       "      <th>svdCF_reco</th>\n",
       "      <th>user_reco</th>\n",
       "      <th>evt_p_reco</th>\n",
       "      <th>evt_c_reco</th>\n",
       "      <th>user_pop</th>\n",
       "      <th>frnd_infl</th>\n",
       "      <th>evt_pop</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>count</th>\n",
       "      <td>10237.000000</td>\n",
       "      <td>1.023700e+04</td>\n",
       "      <td>1.023700e+04</td>\n",
       "      <td>10237.000000</td>\n",
       "      <td>10237.0</td>\n",
       "      <td>10237.0</td>\n",
       "      <td>10237.0</td>\n",
       "      <td>1.023700e+04</td>\n",
       "      <td>10237.0</td>\n",
       "      <td>10237.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>mean</th>\n",
       "      <td>0.039953</td>\n",
       "      <td>9.079033e-05</td>\n",
       "      <td>9.079033e-05</td>\n",
       "      <td>0.094143</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>3.007719e-04</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.002523</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>std</th>\n",
       "      <td>0.195859</td>\n",
       "      <td>3.184999e-18</td>\n",
       "      <td>3.184999e-18</td>\n",
       "      <td>0.186032</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>2.696429e-04</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.009538</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>min</th>\n",
       "      <td>0.000000</td>\n",
       "      <td>9.079033e-05</td>\n",
       "      <td>9.079033e-05</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>2.679976e-07</td>\n",
       "      <td>0.0</td>\n",
       "      <td>-0.021782</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>25%</th>\n",
       "      <td>0.000000</td>\n",
       "      <td>9.079033e-05</td>\n",
       "      <td>9.079033e-05</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1.021071e-04</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.000039</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>50%</th>\n",
       "      <td>0.000000</td>\n",
       "      <td>9.079033e-05</td>\n",
       "      <td>9.079033e-05</td>\n",
       "      <td>0.000091</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>2.251180e-04</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.000507</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>75%</th>\n",
       "      <td>0.000000</td>\n",
       "      <td>9.079033e-05</td>\n",
       "      <td>9.079033e-05</td>\n",
       "      <td>0.076344</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>4.220962e-04</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.001874</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>max</th>\n",
       "      <td>1.000000</td>\n",
       "      <td>9.079033e-05</td>\n",
       "      <td>9.079033e-05</td>\n",
       "      <td>0.983771</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1.300592e-03</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.382623</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "            invited   userCF_reco    evtCF_reco    svdCF_reco  user_reco  \\\n",
       "count  10237.000000  1.023700e+04  1.023700e+04  10237.000000    10237.0   \n",
       "mean       0.039953  9.079033e-05  9.079033e-05      0.094143        0.0   \n",
       "std        0.195859  3.184999e-18  3.184999e-18      0.186032        0.0   \n",
       "min        0.000000  9.079033e-05  9.079033e-05      0.000000        0.0   \n",
       "25%        0.000000  9.079033e-05  9.079033e-05      0.000091        0.0   \n",
       "50%        0.000000  9.079033e-05  9.079033e-05      0.000091        0.0   \n",
       "75%        0.000000  9.079033e-05  9.079033e-05      0.076344        0.0   \n",
       "max        1.000000  9.079033e-05  9.079033e-05      0.983771        0.0   \n",
       "\n",
       "       evt_p_reco  evt_c_reco      user_pop  frnd_infl       evt_pop  \n",
       "count     10237.0     10237.0  1.023700e+04    10237.0  10237.000000  \n",
       "mean          0.0         0.0  3.007719e-04        0.0      0.002523  \n",
       "std           0.0         0.0  2.696429e-04        0.0      0.009538  \n",
       "min           0.0         0.0  2.679976e-07        0.0     -0.021782  \n",
       "25%           0.0         0.0  1.021071e-04        0.0      0.000039  \n",
       "50%           0.0         0.0  2.251180e-04        0.0      0.000507  \n",
       "75%           0.0         0.0  4.220962e-04        0.0      0.001874  \n",
       "max           0.0         0.0  1.300592e-03        0.0      0.382623  "
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rs_test.describe()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
